/*
 * Copyright 2019-2025 the original author or authors.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * https://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.iiifi.kite.security.configuration;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.iiifi.kite.security.model.KiteRestTemplate;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * Http请求配置
 *
 * @author kite@iiifi.com 花朝
 */
@Slf4j
@Configuration
@AllArgsConstructor
@AutoConfigureAfter(ObjectMapper.class)
@ConditionalOnClass(name = "okhttp3.OkHttpClient")
public class KiteRestTemplateConfiguration {
    private final ObjectMapper objectMapper;

    @Bean
    public LoggingInterceptor interceptor() {
        return new LoggingInterceptor();
    }

    @Bean
    @LoadBalanced
    @ConditionalOnProperty(value = "kite.security.load-balanced-enabled", havingValue = "true")
    public KiteRestTemplate kiteRestTemplateLoadBalanced(@Autowired(required = false) LoggingInterceptor interceptor) {
        KiteRestTemplate kiteRestTemplate = new KiteRestTemplate(new OkHttp3ClientHttpRequestFactory());
        if (interceptor != null) {
            kiteRestTemplate.setInterceptors(Collections.singletonList(interceptor));
        }
        configMessageConverters(kiteRestTemplate.getMessageConverters());
        return kiteRestTemplate;
    }

    @Bean
    @ConditionalOnProperty(value = "kite.security.load-balanced-enabled", havingValue = "false", matchIfMissing = true)
    public KiteRestTemplate kiteRestTemplate(@Autowired(required = false) LoggingInterceptor interceptor) {
        KiteRestTemplate kiteRestTemplate = new KiteRestTemplate(new OkHttp3ClientHttpRequestFactory());
        if (interceptor != null) {
            kiteRestTemplate.setInterceptors(Collections.singletonList(interceptor));
        }
        configMessageConverters(kiteRestTemplate.getMessageConverters());
        return kiteRestTemplate;
    }

    private void configMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.removeIf(
                x -> x instanceof StringHttpMessageConverter || x instanceof MappingJackson2HttpMessageConverter);
        converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
        converters.add(new MappingJackson2HttpMessageConverter(objectMapper));
    }

    class LoggingInterceptor implements ClientHttpRequestInterceptor {

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
                throws IOException {
            long t1 = System.nanoTime();

            log.debug("===> {} {}", request.getMethod(), request.getURI());
            request.getHeaders().forEach((name, value) -> {
                log.debug("===  {}: {} ", name, StringUtils.arrayToCommaDelimitedString(value.toArray()));
            });

            ClientHttpResponse response = execution.execute(request, body);

            long t2 = System.nanoTime();
            log.debug("<=== {} {} {} {}ms ", request.getMethod(), request.getURI(), response.getStatusCode().value(),
                    (t2 - t1) / 1e6d);
            return response;
        }
    }
}
